#ifndef G3_3DD_WIICOM_H
#define G3_3DD_WIICOM_H

#include "input.h"
#include "text.h"
#include "gui/gui_widget.h"
#include "math/m_vector.h"
#include "3dd_lua.h"

#include <boost/thread/thread.hpp>
#include "singleton.h"

#ifdef WIN32
    #include <windows.h>

    #ifndef HANDLE
        #define HANDLE unsigned long
    #endif
#endif

// Wiimote communication library
#include <wiiuse.h>

float lowpass_filter (float a);

class WIIMOUSE {
	public:
		WIIMOUSE ();

        G3::VEC3I LastPosition;
        G3::VEC3I Position;
		G3::VEC3I ScreenCenter;
        int ScreenWidth;
        int ScreenHeight;

		uint State;
		uint Mode;

        double Sensitivity;

		void SetScreenSize (int Width, int Height);
		void SetPosition (int x, int y, int z);
		void SetMode (uint mode);
		void Center ();
};

/** @class WIICOM_THREAD
	@brief A functor for the Wiimote communications thread */
class WIICOM_THREAD {
    public:
        /**
            @brief The functor for the communications thread
        */
        void operator()();
};

// Wiimote communication class
class WIICOM: public G3::SINGLETON<WIICOM> {
    friend class WIICOM_THREAD;

	public:
		WIICOM ();
		~WIICOM ();

		// Wiiuse wiimote structs
		wiimote** wiimotes;

		// Wiimote mouse
		WIIMOUSE wiimouse;

		// Status string
		std::string status;

		// How many wiimotes have been found?
		int found;
		// How many of them are connected?
		int connected;
		// Timeout for connecting
		int timeout;

		G3::LOG *log;

		typedef boost::signal3<void, WIIMOUSE *, SDL_Event *, float> SIG_WIIMOUSE_EVENT;
		typedef void (*WIIMOUSE_HANDLER)(WIIMOUSE *Input, SDL_Event* Event, float aElapsedTime);
		typedef boost::signals::connection SIG_CONNECTION;

		SIG_WIIMOUSE_EVENT SigWiimouseDown;
		SIG_WIIMOUSE_EVENT SigWiimouseUp;
		SIG_WIIMOUSE_EVENT SigWiimouseMove;

		vector<SIG_CONNECTION> ConnWiimouseDown;
		vector<SIG_CONNECTION> ConnWiimouseUp;
		vector<SIG_CONNECTION> ConnWiimouseMove;

		SIG_CONNECTION doOnWiimouseDown (WIIMOUSE_HANDLER aWiimouseHandler);
		SIG_CONNECTION doOnWiimouseUp (WIIMOUSE_HANDLER aWiimouseHandler);
		SIG_CONNECTION doOnWiimouseMove (WIIMOUSE_HANDLER aWiimouseHandler);

        /**
            @brief Starts the sorter thread
        */
        void start (int num_wiimotes = 1);
        /**
            @brief Stops the sorter thread
        */
        void stop ();
        /**
            @brief Checks if the sorter thread is online
            @return True if it is and fals if it is not
        */
        bool isOnline ();

		// Updates wiimote input data
		void update (double elapsedTime);

		// Handlers for wiimote events
		void handle_generic_event (wiimote *mote, double elapsedTime);
		void handle_ctrl_status (wiimote *mote);
		void handle_disconnect (wiimote *mote);

	private:
		// Number of wiimotes to search for
		int wiimotes_total;

		double delta_time;

        /** Pointer to the sorter thread */
        boost::thread *thread;
        /** Is the sorter thread online ? */
        bool online;

		// Try to connect to available wiimotes
		int connect ();
};

extern WIICOM wiicom;

class JOY_GAUGE : public G3::GUI::WIDGET {
	public:
		JOY_GAUGE ();
		~JOY_GAUGE ();

		float mag;
		float ang;

		G3::VEC2I verts [30];

		void PreCalc ();

		void Draw (float aElapsedTime = 0.0f);

		uint GetType () { return G3::MainTypeMgr.GetType ("W_JOY_GAUGE"); }

		bool IsStatic () { return true; }
};

extern JOY_GAUGE joy_gauge;
extern float rot_magnitude;
extern G3::VEC2F rot_angle;
extern bool motion_sensing_on;
extern float battery_level;

void DD3RotateAround (double delta, G3::VEC3F axis);

#endif

